package com.cqvip.innocence.common.util.file;

import cn.hutool.core.util.StrUtil;
import com.cqvip.innocence.common.util.regex.RegexUtil;
import com.cqvip.innocence.common.util.yml.YmlReadUtil;
import com.cqvip.innocence.project.model.dto.JsonResult;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.http.MediaType;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Locale;
import java.util.UUID;

import static com.cqvip.innocence.common.constant.ConfigConstant.YML_FILE_NAME;

/**
 * @ClassName FileUtil
 * @Description 文件操作工具类，EasyExcel依赖的poi版本为3.17
 * @Author Innocence
 * @Date 2020/9/11 9:32
 * @Version 1.0
 */
public class FileUtil {

    /**
     * 允许上传的文件类型
     *
     * @author Innocence
     * @date 2020/9/15
     */
    public static final String ALLOWEXTS = YmlReadUtil.getValueToString(YML_FILE_NAME, "myFile.fileAllowExts");

    /**
     * 上传文件的基础位置
     *
     * @author Innocence
     * @date 2020/9/15
     */
    public static final String DIRPATHBASE = YmlReadUtil.getValueToString(YML_FILE_NAME, "myFile.upload-url");

    /**
     * 生成excel的基础路径
     *
     * @author Innocence
     * @date 2020/9/15
     */
    private static final String EXCELURL = YmlReadUtil.getValueToString(YML_FILE_NAME, "myFile.excel-url");

    /**
     * 最大文件限制
     *
     * @author Innocence
     * @date 2022/7/11
     */
    private static final String MAX_FILE_SIZE = YmlReadUtil.getValueToString(YML_FILE_NAME, "spring.servlet.multipart.max-file-size");
    private static final String MAX_VIDEO_SIZE = YmlReadUtil.getValueToString(YML_FILE_NAME, "spring.servlet.multipart.max-file-size");

    private List<String> fileAllowExts;

    {
        fileAllowExts = StrUtil.splitTrim(ALLOWEXTS, ",");
    }

    /**
     * 上传文件并返回相对路径
     *
     * @param file
     * @param basePath 自定义的文件路径
     * @return java.lang.String
     * @author Innocence
     * @date 2020/9/11
     */
    public JsonResult uploadUtil(MultipartFile file, String basePath) {
        if (!file.isEmpty()) {
            String filename = file.getOriginalFilename();
            String type = filename.substring(filename.lastIndexOf(".") + 1);
            if (!fileAllowExts.contains(type)) {
                return JsonResult.Get(false, "不允许的文件类型！");
            }
            Long size = Long.valueOf(file.getSize() / 1024);
            if (size > RegexUtil.getNumByRegex(MAX_FILE_SIZE)) {
                return JsonResult.Get(false, "文件大小超出最大限制！");
            }
            String path;
            if (StrUtil.isNotBlank(basePath)) {
                path = getPath(DIRPATHBASE + File.separator + basePath);
            } else {
                path = getPath(DIRPATHBASE);
            }
            String filePath = path + File.separator + UUID.randomUUID() + "." + type;
            File newFile = new File(filePath);
            FileOutputStream outputStream = null;
            BufferedOutputStream out = null;
            try {
                outputStream = new FileOutputStream(newFile);
                out = new BufferedOutputStream(outputStream);
                out.write(file.getBytes());
                out.flush();
                String relativePath = filePath.substring(filePath.lastIndexOf(DIRPATHBASE) - 1);
                return JsonResult.Get(true, relativePath).put("title", filename).put("size", size);
            } catch (FileNotFoundException e) {
                return JsonResult.Get(false, "找不到文件位置");
            } catch (IOException e) {
                return JsonResult.Get(false, "文件IO流异常");
            } finally {
                try {
                    out.close();
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 上传文件并返回相对路径(结合网站所配置的扩展名和文件大小)
     *
     * @param file
     * @param basePath
     * @param extensionArray
     * @param limit
     * @return
     */
    public JsonResult uploadUtil(MultipartFile file, String basePath, List<String> extensionArray, Long limit) {
        if (!file.isEmpty()) {
            String filename = file.getOriginalFilename();
            String type = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase(Locale.ROOT);
            extensionArray = extensionArray.size() == 0 ? fileAllowExts : extensionArray;

            if (type.equals("mp4") || type.equals("flv") || type.equals("avi")) {
                limit = limit == null ? RegexUtil.getNumByRegex(MAX_VIDEO_SIZE) * 1024 * 1024L : limit;
            } else {
                limit = limit == null ? RegexUtil.getNumByRegex(MAX_FILE_SIZE) * 1024 * 1024L : limit;
            }
            if (!extensionArray.contains(type)) {
                return JsonResult.Get(false, "不允许的文件类型！");
            }
            Long size = Long.valueOf(file.getSize());
            if (size > limit) {
                return JsonResult.Get(false, "文件大小超出最大限制！");
            }
            String path;
            if (StrUtil.isNotBlank(basePath)) {
                path = getPath(DIRPATHBASE + File.separator + basePath);
            } else {
                path = getPath(DIRPATHBASE);
            }
            String filePath = path + File.separator + UUID.randomUUID() + "." + type;
            File newFile = new File(filePath);
            FileOutputStream outputStream = null;
            BufferedOutputStream out = null;
            try {
                outputStream = new FileOutputStream(newFile);
                out = new BufferedOutputStream(outputStream);
                out.write(file.getBytes());
                out.flush();
                String relativePath = filePath.substring(filePath.lastIndexOf(DIRPATHBASE) - 1);
                return JsonResult.Get(true, relativePath).put("title", filename).put("size", size);
            } catch (FileNotFoundException e) {
                return JsonResult.Get(false, "找不到文件位置");
            } catch (IOException e) {
                return JsonResult.Get(false, "文件IO流异常");
            } finally {
                try {
                    out.close();
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return JsonResult.Get(false, "无法上传空文件！请重试！");
    }


    /**
     * 下载
     *
     * @param request, response, path
     * @return com.cqvip.innocence.project.model.dto.JsonResult
     * @author Innocence
     * @date 2020/9/11
     */
    public void download(HttpServletRequest request, HttpServletResponse response, String path, String title) throws Exception {
        response.setContentType("text/html;charset=UTF-8");
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            request.setCharacterEncoding("utf-8");
//            String downLoadPath = request.getSession().getServletContext().getRealPath("/") + path;
            File fileModel = new File(path);
            long fileLength = fileModel.length();
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            String s = "";

            if (StrUtil.isNotBlank(title)) {
                s =  URLEncoder.encode(title,StandardCharsets.UTF_8.toString());
            } else {
                s =  URLEncoder.encode(fileModel.getName(),StandardCharsets.UTF_8.toString());
            }
            response.setHeader("Content-disposition", "attachment; filename=" + s);
            response.setHeader("Access-Control-Expose-Headers", "Content-disposition");
            response.setHeader("Content-Length", String.valueOf(fileLength));
            bis = new BufferedInputStream(new FileInputStream(path));
            bos = new BufferedOutputStream(response.getOutputStream());
            byte[] buff = new byte[2048];
            int bytesRead;
            while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                bos.write(buff, 0, bytesRead);
            }
            bis.close();
            bos.close();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除文件
     *
     * @param path 文件绝对路径
     * @return boolean
     * @author Innocence
     * @date 2020/9/11
     */
    public boolean deleteFile(String path) {
        File file = new File(path);
        if (file.isFile() && file.exists()) {
            return file.delete();
        }
        return false;
    }

    /**
     * 根据文件的相对路径和项目配置删除文件
     *
     * @param path 相对路径
     * @return boolean
     * @author Innocence
     * @date 2022/7/13
     */
    public boolean deleteFileByRelativePath(String path) {
        String targetPath = getPath(DIRPATHBASE) + path;
        File file = new File(targetPath);
        if (file.isFile() && file.exists()) {
            return file.delete();
        }
        return false;
    }

    /**
     * 获取当前系统路径
     */
    public String getPath(String basePath) {
        File path = null;
        try {
            path = new File(ResourceUtils.getURL("classpath:").getPath());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        if (!path.exists()) {
            path = new File("");
        }
        File upload = new File(path.getAbsolutePath(), "static/" + basePath);
        if (!upload.exists()) {
            upload.mkdirs();
        }
        return upload.getAbsolutePath();
    }

    /**
     * 运行获取项目target路径 jar包运行获取jar包同级路径
     *
     * @return java.lang.String
     * @author Innocence
     * @date 2020/11/25
     */
    public String getTargetPath() {
        ApplicationHome applicationHome = new ApplicationHome(getClass());
        File source = applicationHome.getSource();
        String targetPath = source.getParentFile().toString();
        return targetPath;
    }

    /**
     * byte数组转文件
     *
     * @param buffer
     * @param filePath
     * @return void
     * @author Innocence
     * @date 2020/11/25
     */
    public void bytesToFile(byte[] buffer, String filePath) {
        File file = new File(filePath);
        OutputStream output = null;
        BufferedOutputStream bufferedOutput = null;
        try {
            output = new FileOutputStream(file);
            bufferedOutput = new BufferedOutputStream(output);
            bufferedOutput.write(buffer);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != bufferedOutput) {
                try {
                    bufferedOutput.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != output) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
